package service

import (
	"bytes"
	"cgs-server/helper"
	"cgs-server/internal/cgserver/events"
	"cgs-server/server"
	"cgs-server/server/cgs/app/models"
	"cgs-server/server/cgs/app/models/dto"
	v1 "cgs-server/server/cgs/app/models/v1"
	"cgs-server/server/cgs/app/models/vo"
	"cgs-server/server/cgs/app/store"
	"cgs-server/server/model"
	"context"
	"errors"
	"github.com/gookit/event"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"log"
	"strings"
	"time"
)

type WorksheetRowsSrv interface {
	Get(rowId string, worksheetId string, user *model.User) (*vo.WorksheetRow, error)
	Save(row *models.WorksheetRow, user *model.User) error
	Delete(rowId string, worksheetId string, user *model.User) error
	Update(ctx context.Context, row *models.WorksheetRow, user *model.User) error
	List(param *models.FilterParam, user *model.User) (*server.PageResult, error)

	BatchAddRow(wr *models.WorksheetRows, user *model.User) error
	BatchUpdateRow(wr *dto.BatchUpdateRow, user *model.User) error
	BatchDeleteRow(wr *dto.BatchUpdateRow, user *model.User) error

	SavePublic(row *models.WorksheetRow, user *model.User) error
}

type worksheetRowsSrv struct {
	store store.Factory
}

func (w *worksheetRowsSrv) BatchDeleteRow(wr *dto.BatchUpdateRow, user *model.User) error {
	filter := wr.Filters.ResolveFilterParam()
	if len(wr.RowIds) > 0 {
		filter["rowId"] = bson.M{
			"$in": wr.RowIds,
		}
	}
	if wr.IsAll {
		filter = bson.M{}
	} else {
		if len(filter) == 0 {
			return nil
		}
	}
	opts := v1.DeleteOptions{}
	opts.SetFilter(&filter)
	err := w.store.WorksheetRows().BatchDeleteRow(&wr.WorksheetRow, user, opts)
	return err
}

func (w *worksheetRowsSrv) BatchUpdateRow(wr *dto.BatchUpdateRow, user *model.User) error {
	filter := wr.Filters.ResolveFilterParam()
	if len(wr.RowIds) > 0 {
		filter["rowId"] = bson.M{
			"$in": wr.RowIds,
		}
	}
	if wr.IsAll {
		filter = bson.M{}
	}
	opts := v1.UpdateOptions{}
	opts.SetFilter(&filter)
	err := w.store.WorksheetRows().BatchUpdateRow(&wr.WorksheetRow, user, opts)
	return err
}

func (w *worksheetRowsSrv) BatchAddRow(wr *models.WorksheetRows, user *model.User) error {
	//TODO license 校验
	// 处理字段数据
	wsInfoObjId, err := primitive.ObjectIDFromHex(wr.WorksheetId)
	if err != nil {
		return err
	}
	wsInfo, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: wsInfoObjId}, user, v1.GetOptions{})
	if err != nil {
		return err
	}

	return w.batchAddRow(wr, user, wsInfo.Fields)
}

func (w *worksheetRowsSrv) batchAddRow(wr *models.WorksheetRows, user *model.User, fields *models.Fields) error {
	var err error
	rowDataList := wr.GetWsRowData()
	for _, row := range rowDataList {
		err = row.TransferData(fields, user)
		if err != nil {
			return err
		}
	}

	err = w.store.WorksheetRows().BatchAddRow(rowDataList, user, v1.CreateOptions{})
	return err
}

func (w *worksheetRowsSrv) List(param *models.FilterParam, user *model.User) (*server.PageResult, error) {
	wsInfoObjId, err := primitive.ObjectIDFromHex(param.WorksheetId)
	if err != nil {
		return nil, err
	}
	wsInfo, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: wsInfoObjId}, user, v1.GetOptions{})
	if err != nil {
		return nil, err
	}
	// 这里 wsInfo.Fields 的值可能为 nil
	if wsInfo.Fields == nil {
		wsInfo.Fields = &models.Fields{}
	}

	return w.list(param, user, wsInfo.Fields, wsInfo)
}

func (w *worksheetRowsSrv) list(param *models.FilterParam, user *model.User, fields *models.Fields, wsInfo *vo.WorksheetInfo) (*server.PageResult, error) {
	// 权限控制
	_, err := getAppAuths(wsInfo.AppId, user)
	if err != nil {
		return nil, err
	}
	opts := v1.ListOptions{}
	filterParam := param.ResolveFilterParam(*fields)
	var pageNo int64
	var pageSize int64
	if user.IsFormAuthTypeDistributeAll(wsInfo.AppId) {
		if !user.HasAuth(wsInfo.AppId, server.EditForm, server.EditForm2, server.EditForm4) && user.HasAuth(wsInfo.AppId, server.EditForm3) {
			filterParam["owner"] = user.GetId()
		}
	} else {
		if user.HasFormAuth(wsInfo.AppId, wsInfo.Id.Hex(), server.RowReadAll) {

		} else if user.HasFormAuth(wsInfo.AppId, wsInfo.Id.Hex(), server.RowReadOwn) {
			filterParam["owner"] = user.GetId()
		} else {
			// 没有读的权限
			return &server.PageResult{
				CgsResult: server.CgsResult{
					Code:    200,
					Msg:     "Get Successfully!",
					Data:    []interface{}{},
					Success: true,
				},
				PageNo:     pageNo,
				PageSize:   pageSize,
				TotalCount: 0,
			}, nil
		}
	}

	opts.SetFilter(&filterParam)
	if param.PageNo != nil && param.PageSize != nil {
		opts.SetPage(*param.PageNo, *param.PageSize)
		pageNo = *param.PageNo
		pageSize = *param.PageSize
	}
	opts.SetFindOptions(param.ResolveOptions())

	wr := &models.WorksheetRow{WorksheetId: param.WorksheetId}

	list, err := w.store.WorksheetRows().List(wr, user, opts)
	if err != nil {
		return nil, err
	}

	// 这里的format比较耗时，暂时也可以不用格式化
	if models.NeedFormat(fields) {
		for _, row := range *list {
			data, err := row.Data.FormatData(fields)
			if err != nil {
				return nil, err
			}
			row.Data = data
		}
	}

	countOpts := v1.CountOptions{}
	countOpts.SetFilter(&filterParam)
	count, err := w.store.WorksheetRows().Count(wr, user, countOpts)
	if err != nil {
		return nil, err
	}

	result := server.PageResult{
		CgsResult: server.CgsResult{
			Code:    200,
			Msg:     "Get Successfully!",
			Data:    list,
			Success: true,
		},
		PageNo:     pageNo,
		PageSize:   pageSize,
		TotalCount: count,
	}
	if param.PageNo == nil || param.PageSize == nil {
		result.PageNo = 1
		result.PageSize = count
	}
	result.CalculateTotalPage()

	if param.Format != nil && *param.Format == 1 {
		resultArr := bson.A{}
		for _, field := range *fields {
			// 隐藏的字段
			hidden := field.Options.Value("hidden")
			if hidden != nil && hidden.(bool) == true {
				continue
			}

			data := bson.M{
				"name":     field.Name,
				"alia":     field.Alia,
				"dataType": field.DataType,
				"options":  field.Options,
			}
			arr := bson.A{}
			flag := false

			for _, row := range *list {
				for k, v := range row.Data {
					if k == field.Name {
						arr = append(arr, v)
						flag = true
						break
					}
				}
				if !flag {
					// 这条记录没有这个字段的值，补上一个默认值
					arr = append(arr, "")
				}
				flag = false
			}
			data["data"] = arr

			resultArr = append(resultArr, data)
		}

		result.Data = resultArr
	}

	return &result, err
}

func (w *worksheetRowsSrv) Update(ctx context.Context, row *models.WorksheetRow, user *model.User) error {
	// 处理字段数据
	if row.RowId == "" {
		return errors.New("row id is required")
	}
	wsInfoObjId, err := primitive.ObjectIDFromHex(row.WorksheetId)
	if err != nil {
		return err
	}
	wsInfo, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: wsInfoObjId}, user, v1.GetOptions{})
	if err != nil {
		return err
	}
	if err := w.update(ctx, row, user, wsInfo.Fields); err != nil {
		return err
	}

	{
		get, err := w.Get(row.GetId(), row.WorksheetId, user)
		if err == nil {
			server.WebsocketHub.Send(&server.BroadcastMessage{Type: models.UpdateRow, Data: get})
		}

		data := event.M{}
		err = helper.TransformType(get, &data)
		if err == nil {
			if user != nil {
				data["tenantId"] = user.GetTenantId()
			}
			event.Fire(events.AppRowUpdate, data)
		}
	}

	{
		// 触发工作流
		// 1. 查询所有自动触发的工作流数据
		opts := v1.ListOptions{}
		opts.AddFilter("autoTrigger", true)
		configList, err := w.store.App().ListConfig(&dto.Config{VisualType: "Workflow"}, user, opts)
		if err != nil {

		} else {
			token := ctx.Value("token")

			for _, config := range *configList {
				if config.RequestData != "" {
					if !strings.Contains(config.Detail, row.WorksheetId) {
						continue
					}
					go triggerWorkflow(token.(string), config)
				}
			}
		}
	}

	return err
}

func (w *worksheetRowsSrv) update(ctx context.Context, row *models.WorksheetRow, user *model.User, fields *models.Fields) error {
	if err := row.TransferData(fields, user); err != nil {
		return err
	}
	// 分离子表数据
	data := row.SubFormRowData(fields)

	err := w.store.WorksheetRows().Update(row, user, v1.UpdateOptions{})
	if err != nil {
		return err
	}
	// 更新子表数据
	if data != nil {
		for _, field := range *fields {
			if !field.IsSubForm() {
				continue
			}
			d := data.DataByName(field.Name)
			if d == nil {
				continue
			}
			dataArr, ok := d.([]interface{})
			if !ok {
				continue
			}

			for _, d := range dataArr {
				data, ok := d.(map[string]interface{})
				if !ok {
					continue
				}

				subRow := &models.WorksheetRow{
					WorksheetId: field.SubFormId,
					Data:        data,
				}
				if data["rowId"] == nil {
					// 新增
					subRow.RelationRowId = row.GetId()
					if err := w.saveRow(subRow, user, field.SubFields); err != nil {
						return err
					}
				} else {
					// 更新
					subRow.RowId = data["rowId"].(string)
					err := w.update(context.TODO(), subRow, user, field.SubFields)
					if err != nil {
						return err
					}
				}
			}

			if err != nil {
				return err
			}
		}
	}

	return nil
}

func triggerWorkflow(token string, config *vo.Config) {
	data := bson.A{}
	err := helper.FromJSON([]byte(config.RequestData), &data)
	if err != nil {
		return
	}
	d := bson.M{"data": data}
	toJSON, err := helper.ToJSON(d)
	if err != nil {
		return
	}

	_, err = helper.Request("http://39.99.130.9:7889/workflow/start", bson.M{
		"method": "POST",
		"body":   bytes.NewReader(toJSON),
		"headers": bson.M{
			"Content-Type": "application/json",
			"Auth-Token":   token,
		},
	})
	if err != nil {
		log.Println("工作流执行错误", err)
	} else {

	}
}

func (w *worksheetRowsSrv) Delete(rowId string, worksheetId string, user *model.User) error {
	get, err2 := w.Get(rowId, worksheetId, user)

	err := w.store.WorksheetRows().Delete(&models.WorksheetRow{RowId: rowId, WorksheetId: worksheetId}, user, v1.DeleteOptions{})
	if err != nil {
		return err
	}

	if err2 == nil {
		server.WebsocketHub.Send(&server.BroadcastMessage{Type: models.DeleteRow, Data: get})

		data := event.M{}
		err := helper.TransformType(get, &data)
		if err == nil {
			if user != nil {
				data["tenantId"] = user.GetTenantId()
			}
			event.Fire(events.AppRowDelete, data)
		}
	}

	return err
}

func (w *worksheetRowsSrv) Save(row *models.WorksheetRow, user *model.User) error {
	// 处理字段数据
	wsInfoObjId, err := primitive.ObjectIDFromHex(row.WorksheetId)
	if err != nil {
		return err
	}
	wsInfo, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: wsInfoObjId}, user, v1.GetOptions{})
	if err != nil {
		return err
	}
	if err := w.saveRow(row, user, wsInfo.Fields); err != nil {
		return err
	}

	{
		get, err := w.Get(row.GetId(), row.WorksheetId, user)
		if err == nil {
			server.WebsocketHub.Send(&server.BroadcastMessage{Type: models.AddRow, Data: get})

			data := event.M{}
			err := helper.TransformType(get, &data)
			if err == nil {
				if user != nil {
					data["tenantId"] = user.GetTenantId()
				}
				go event.Fire(events.AppRowSave, data)
			}
		}
	}
	return err
}

func (w *worksheetRowsSrv) SavePublic(row *models.WorksheetRow, user *model.User) error {
	// 先判断填写方式
	opt := v1.GetOptions{}
	opt.AddFilter("worksheetId", row.WorksheetId)
	pw, err := w.store.PublicWorksheet().Get(&models.PublicWorksheet{}, user, opt)
	if err != nil {
		return err
	}
	if pw.Enabled == nil || !*pw.Enabled {
		return errors.New("worksheet is not shared")
	}

	if pw.FillTimes == nil {
		return errors.New("worksheet is not shared")
	}

	fillTime := *pw.FillTimes

	if fillTime == models.FillOnce && pw.LastFillTime != nil {
		return errors.New("表单只能填写一次")
	}
	if fillTime == models.FillOnceEveryDay && pw.LastFillTime != nil {
		after := helper.GetZeroTime(time.Now()).After(*pw.LastFillTime)
		if !after {
			return errors.New("表单每天只能填写一次")
		}
	}

	// 处理字段数据
	wsInfoObjId, err := primitive.ObjectIDFromHex(row.WorksheetId)
	if err != nil {
		return err
	}
	wsInfo, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: wsInfoObjId}, user, v1.GetOptions{})
	if err != nil {
		return err
	}
	if err := w.saveRow(row, user, wsInfo.Fields); err != nil {
		return err
	}

	// 更新表单设置
	now := time.Now()
	updateOpt := v1.UpdateOptions{}
	updateOpt.AddFilter("worksheetId", row.WorksheetId)
	err = w.store.PublicWorksheet().Update(&models.PublicWorksheet{LastFillTime: &now}, user, updateOpt)

	if err != nil {
		return err
	}

	{
		get, err := w.Get(row.GetId(), row.WorksheetId, user)
		if err == nil {
			server.WebsocketHub.Send(&server.BroadcastMessage{Type: models.AddRow, Data: get})

			data := event.M{}
			err := helper.TransformType(get, &data)
			if err == nil {
				if user != nil {
					data["tenantId"] = user.GetTenantId()
					data["userId"] = user.GetId()
				}
				event.AsyncFire(event.NewBasic(events.AppRowSave, data))
			}
		}
	}

	return err
}

func (w *worksheetRowsSrv) saveRow(row *models.WorksheetRow, user *model.User, fields *models.Fields) error {
	if err := row.TransferData(fields, user); err != nil {
		return err
	}
	// 分离子表数据
	data := row.SubFormRowData(fields)

	// todo license校验
	// todo websocket推送

	err := w.store.WorksheetRows().Save(row, user, v1.CreateOptions{})
	if err != nil {
		return err
	}

	// 保存子表数据
	if data != nil {
		for _, field := range *fields {
			if !field.IsSubForm() {
				continue
			}
			d := data.DataByName(field.Name)
			if d == nil {
				continue
			}
			dataArr, ok := d.([]interface{})
			if !ok {
				continue
			}
			values := make([]models.RowData, 0, len(dataArr))
			for _, d := range dataArr {
				data, ok := d.(map[string]interface{})
				if !ok {
					continue
				}
				row := models.RowData(data)
				values = append(values, row)
			}
			rows := models.WorksheetRows{
				WorksheetId:   field.SubFormId,
				Rows:          &values,
				RelationRowId: row.GetId(),
			}
			err = w.batchAddRow(&rows, user, field.SubFields)
			if err != nil {
				return err
			}
		}
	}

	return nil
}

func (w *worksheetRowsSrv) Get(rowId string, worksheetId string, user *model.User) (*vo.WorksheetRow, error) {
	get, err := w.store.WorksheetRows().Get(&models.WorksheetRow{RowId: rowId, WorksheetId: worksheetId}, user, v1.GetOptions{})
	if err != nil {
		return nil, err
	}
	// 处理字段数据
	objId, err := primitive.ObjectIDFromHex(get.WorksheetId)
	if err == nil {
		wsInfo, err := w.store.WorksheetInfo().Get(&models.WorksheetInfo{Id: objId}, user, v1.GetOptions{})
		if err == nil {
			data, err := get.Data.FormatData(wsInfo.Fields)
			if err != nil {
				return nil, err
			}
			// todo 查询子表
			for _, field := range *wsInfo.Fields {
				if !field.IsSubForm() {
					continue
				}
				param := &models.FilterParam{
					WorksheetId:   field.SubFormId,
					RelationRowId: rowId,
				}
				list, err := w.list(param, user, field.SubFields, wsInfo)
				if err != nil {
					return nil, err
				}
				data[field.Name] = list.Data
			}

			get.Data = data
		}
	}

	return get, err
}

func newWorksheetRowsSrv(s *service) WorksheetRowsSrv {
	return &worksheetRowsSrv{
		store: s.store,
	}
}
